using System.Text;
using Newtonsoft.Json;
using NotifyCenter.Sender.Options; 

namespace NotifyCenter.Sender;

/// <summary>
/// Mock sender that appends messages to a local text file for demo purposes.
/// </summary>
public class MockFileSender : ISender
{
    public string Type => "MockFileMessage";

    public async Task SendAsync(string configurationJson, string receiver, string content, CancellationToken cancellationToken = default)
    {
        var config = DeserializeConfiguration(configurationJson);
        var filePath = ResolveOutputPath(config.OutputPath);
        var directory = Path.GetDirectoryName(filePath);
        if (!string.IsNullOrWhiteSpace(directory))
        {
            Directory.CreateDirectory(directory);
        }

        var entry = BuildEntry(config, receiver, content);
        await AppendEntryAsync(filePath, entry, cancellationToken);
    }

    private static MockFileSenderConfiguration DeserializeConfiguration(string configurationJson)
    {
        if (string.IsNullOrWhiteSpace(configurationJson))
        {
            return new MockFileSenderConfiguration();
        }

        try
        {
            var config = JsonConvert.DeserializeObject<MockFileSenderConfiguration>(configurationJson);
            return config ?? new MockFileSenderConfiguration();
        }
        catch (JsonException ex)
        {
            throw new InvalidOperationException("configurationJson must be a valid MockFileSenderConfiguration json.", ex);
        }
    }

    private static string ResolveOutputPath(string? configuredPath)
    {
        var path = string.IsNullOrWhiteSpace(configuredPath)
            ? MockFileSenderConfiguration.DefaultOutputPath
            : configuredPath!;

        if (Path.IsPathRooted(path))
        {
            return Path.GetFullPath(path);
        }

        var baseDir = AppContext.BaseDirectory ?? Directory.GetCurrentDirectory();
        return Path.GetFullPath(Path.Combine(baseDir, path));
    }

    private static string BuildEntry(MockFileSenderConfiguration config, string receiver, string content)
    {
        var builder = new StringBuilder();
        if (config.AppendTimestamp)
        {
            builder.Append('[')
                .Append(DateTimeOffset.UtcNow.ToString("O"))
                .Append("] ");
        }

        builder.AppendLine("NotifyCenter Mock Sender");
        if (!string.IsNullOrWhiteSpace(receiver))
        {
            builder.AppendLine($"Receiver: {receiver}");
        }

        builder.AppendLine("Content:");
        builder.AppendLine(string.IsNullOrWhiteSpace(content) ? "<empty>" : content);
        builder.AppendLine(new string('-', 40));
        builder.AppendLine();

        return builder.ToString();
    }

    private static Task AppendEntryAsync(string filePath, string entry, CancellationToken cancellationToken)
    {
        var encodedEntry = Encoding.UTF8.GetBytes(entry);
        return AppendBytesAsync(filePath, encodedEntry, cancellationToken);
    }

    private static async Task AppendBytesAsync(string filePath, byte[] data, CancellationToken cancellationToken)
    {
        await using var stream = new FileStream(
            filePath,
            FileMode.Append,
            FileAccess.Write,
            FileShare.Read,
            bufferSize: 4096,
            useAsync: true);
        await stream.WriteAsync(data, 0, data.Length, cancellationToken);
    }
}
